﻿/**
  ******************************************************************************
  * @file    Libraries/Device/JS32T031/JS32T031_LL_Driver/src/js32t031_ll_eflash.c
  * @author  JUSHENG Application Team
  * @version V1.0.0
  * @date    02-19-2022
  * @brief   This file contains all the EFLASH LL firmware functions.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2022 JUSHENG</center></h2>
  *
  *
  *
  ******************************************************************************
  */ 

/* Includes ------------------------------------------------------------------*/
#include "include.h"
#include "js32t031_ll_eflash.h"

/** @addtogroup JS32T031_StdPeriph_Driver JS32T031 Driver
  * @{
  */
  
/** @defgroup eflash_interface_gr EFLASH Driver
  * @ingroup  JS32T031_StdPeriph_Driver
  * @{
  */

/** @addtogroup EFLASH_LL_Driver EFLASH LL Driver
  * @ingroup  eflash_interface_gr
  * @{
  */
  
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup EFLASH_LL_Inti_Cfg EFLASH LL Initialization And Configuration
  * @ingroup  EFLASH_LL_Driver
  * @brief    EFLASH LL Initialization And Configuration
  * @{
  */

/**
  * @brief  ll_eflash_init
  * @param  p_eflash: Base address of eflash register
  * @param  p_init: TYPE_LL_EFLASH_INIT pointer to eflash init stuct
  * @retval None
  * @note eflash clk : 26Mhz safty, but Need to be set to 8M on the FPGA
  */
void ll_eflash_init(EFLASH_TypeDef *p_eflash, TYPE_LL_EFLASH_INIT *p_init)
{
#if FPGA_EN
#define RC_TIME         (((SYS_CLK/1000000 + 7)/8)-1)
#else
#define RC_TIME         (((SYS_CLK/1000000 + 25)/26)-1)
#endif
    ll_eflash_timing_set(
        p_eflash, 
        LL_EF_TIME_REG0_RC(RC_TIME)|LL_EF_TIME_REG0_RW(4)|LL_EF_TIME_REG0_ADH(0)|LL_EF_TIME_REG0_ADS(4)|LL_EF_TIME_REG0_PGH(0),
        LL_EF_TIME_REG1_US(((SYS_CLK/1000000) + 2)) | LL_EF_TIME_REG1_MS(1000)
    );

    //eflash_main_lock(EFLASHx, UNLOCK);
    //eflash_nvr_lock(EFLASHx, UNLOCK);

    ll_eflash_clk_sel(p_eflash, LL_EF_PROG_CLK_RC2DIV);
    
}

/**
  * @brief  ll_eflash_nvr_lock
  * @param  p_eflash: Base address of eflash register
  * @param  isLock: Whether to lock
  * @retval None
  */
void ll_eflash_nvr_lock(EFLASH_TypeDef *p_eflash, TYPE_ENUM_LL_EF_LOCK isLock){
    if(isLock){
        p_eflash->NVR_PASSWORD = 0x0;
    } else {
        p_eflash->NVR_PASSWORD = LL_EF_HW_NVR_PASSWORD;
    }
}

/**
  * @brief  ll_eflash_main_lock
  * @param  p_eflash: Base address of eflash register
  * @param  isLock: Whether to lock
  * @retval None
  */
void ll_eflash_main_lock(EFLASH_TypeDef *p_eflash, TYPE_ENUM_LL_EF_LOCK isLock){
    if(isLock){
        p_eflash->MAIN_PASSWORD = 0x0;
    } else {
        p_eflash->MAIN_PASSWORD = LL_EF_HW_MAIN_PASSWORD;
    }
}

/**
  * @brief  ll_eflash_timing_set
  * @param  p_eflash: Base address of eflash register
  * @param  time_reg0: timer register0
  * @param  time_reg1: timer register1
  * @retval None
  */
void ll_eflash_timing_set(EFLASH_TypeDef *p_eflash, u32 time_reg0, u32 time_reg1)
{
    p_eflash->TIME_REG0 = time_reg0;
    /* p_eflash->TIME_REG1 = time_reg1 & 0xFF; */
}

/**
  * @brief  ll_eflash_clk_sel_exosc
  * @param  p_eflash: Base address of eflash register
  * @retval None
  * @note osc clk : 26Mhz
  */
void ll_eflash_clk_sel(EFLASH_TypeDef *p_eflash, TYPE_ENUM_LL_EF_PROG_CLK_SEL exosc_sel)
{
    if(LL_EF_PROG_CLK_EXOSC == exosc_sel){
        p_eflash->CTRLR0 |= LL_EF_CTRLR0_PROG_CLK_EXOSC_SEL;
    } else {
        p_eflash->CTRLR0 &= ~LL_EF_CTRLR0_PROG_CLK_EXOSC_SEL;
    }
}

/**
  * @}
  */

/** @defgroup EFLASH_LL_Data_Transfers EFLASH LL Data transfers functions
  * @ingroup  EFLASH_LL_Driver
  * @brief    EFLASH LL Data transfers functions 
  * @{
  */

/**
  * @brief  ll_eflash_prog_one_data_main
  * @param  p_eflash: Base address of eflash register
  * @param  addr: Write data address in eflash
  * @param  data: Write data to eflash
  * @retval None
  */
void ll_eflash_prog_one_data_main(EFLASH_TypeDef *p_eflash, u32 addr, u32 data)
{
//    if(prog_byte_num > LL_EF_PROG_BYTE_NUM4)
//    {
//        return;
//    }
//    if(LL_EF_PROG_BYTE_NUM2 == prog_byte_num)
//    {
//       addr &= 0x1FFFFFFE;
//    }
//    else if(LL_EF_PROG_BYTE_NUM4 == prog_byte_num)
//    {
       addr &= 0xFFFC;
//    }
    while((p_eflash->DONE & LL_EF_DONE_PROG_DONE) != LL_EF_DONE_PROG_DONE)
    {
//        u32 tmp_val = 0;
//        tmp_val = 1;
    }
    ll_eflash_main_lock(p_eflash, LL_EF_UNLOCK);
    
    p_eflash->PROG_ADDR = LL_EF_PROG_ADDR_PROG_BYTE_ADDR(addr);
    
    p_eflash->PROG_DATA = data;

    while((p_eflash->DONE & LL_EF_DONE_PROG_DONE) != LL_EF_DONE_PROG_DONE);
}

/**
  * @brief  ll_eflash_prog_one_data_nvr
  * @param  p_eflash: Base address of eflash register
  * @param  addr: Write data address in eflash
  * @param  data: Write data to eflash
  * @retval None
  */
void ll_eflash_prog_one_data_nvr(EFLASH_TypeDef *p_eflash, u32 addr, u32 data)
{
//    if(prog_byte_num > LL_EF_PROG_BYTE_NUM4)
//    {
//        return;
//    }
//    if(LL_EF_PROG_BYTE_NUM2 == prog_byte_num)
//    {
//       addr &= 0x1FFFFFFE;
//    }
//    else if(LL_EF_PROG_BYTE_NUM4 == prog_byte_num)
//    {
       addr &= 0xFFFC;
//    }
    while((p_eflash->DONE & LL_EF_DONE_PROG_DONE) != LL_EF_DONE_PROG_DONE);
    
    ll_eflash_nvr_lock(p_eflash, LL_EF_UNLOCK);
    
    p_eflash->PROG_ADDR = LL_EF_PROG_ADDR_PROG_BYTE_ADDR(addr) | LL_EF_PROG_ADDR_PROG_NVR_EN;
  
    p_eflash->PROG_DATA = data;

    while((p_eflash->DONE & LL_EF_DONE_PROG_DONE) != LL_EF_DONE_PROG_DONE);
}

/**
  * @brief  ll_eflash_prog_one_data include main and nvr
  * @param  p_eflash: Base address of eflash register
  * @param  addr: Write data address in eflash
  * @param  data: Write data to eflash
  * @retval None
  */
void ll_eflash_prog_one_data(EFLASH_TypeDef *p_eflash, u32 addr, u32 data)
{
    if(addr < LL_EF_MAIN_SECTOR_NUM * LL_EF_SECTOR_SIZE)
    {
        ll_eflash_prog_one_data_main(p_eflash, addr, data);
    }
    else
    {
        ll_eflash_prog_one_data_nvr(p_eflash, addr, data);
    }
}

/**
  * @brief  ll_eflash_erase_one_sector_main
  * @param  p_eflash: Base address of eflash register
  * @param  sect_num: The number of the sector in eflash
  * @retval None
  */
void ll_eflash_erase_one_sector_main(EFLASH_TypeDef *p_eflash, u16 sect_num)
{
    if(sect_num < LL_EF_MAIN_SECTOR_NUM)
    {
        while((p_eflash->DONE & LL_EF_DONE_SECT_ERASE_DONE) != LL_EF_DONE_SECT_ERASE_DONE);
        
        ll_eflash_main_lock(p_eflash, LL_EF_UNLOCK);

        p_eflash->ERASE_CTRL = LL_EF_ERASE_CTRL_SECTOR_ERASE_KICK_START | LL_EF_ERASE_CTRL_ERASE_SECTOR_ADDR(sect_num);

        while((p_eflash->DONE & LL_EF_DONE_SECT_ERASE_DONE) != LL_EF_DONE_SECT_ERASE_DONE);
    }
}

/**
  * @brief  ll_eflash_erase_one_sector_NVR
  * @param  p_eflash: Base address of eflash register
  * @param  sect_num: The number of the sector in eflash
  * @retval None
  */
void ll_eflash_erase_one_sector_nvr(EFLASH_TypeDef *p_eflash, u16 sect_num)
{
    if(sect_num < LL_EF_NVR_SECTOR_NUM)
    {
        while((p_eflash->DONE & LL_EF_DONE_SECT_ERASE_DONE) != LL_EF_DONE_SECT_ERASE_DONE);
        
        ll_eflash_nvr_lock(p_eflash, LL_EF_UNLOCK);

        p_eflash->ERASE_CTRL = LL_EF_ERASE_CTRL_SECTOR_ERASE_KICK_START |
                               LL_EF_ERASE_CTRL_SECTOR_NVR_SEL |
                               LL_EF_ERASE_CTRL_ERASE_SECTOR_ADDR(sect_num);
        while((p_eflash->DONE & LL_EF_DONE_SECT_ERASE_DONE) != LL_EF_DONE_SECT_ERASE_DONE);
    }
}

/**
  * @brief  ll_eflash_erase_one_sector include main sector and nvr sector
  * @param  p_eflash: Base address of eflash register
  * @param  sect_num: The number of the sector in eflash
  * @retval None
  */
void ll_eflash_erase_one_sector(EFLASH_TypeDef *p_eflash, u16 sect_num)
{
    if(sect_num < LL_EF_MAIN_SECTOR_NUM)
    {
        ll_eflash_erase_one_sector_main(p_eflash, sect_num);
    }
    else if(sect_num < LL_EF_MAIN_NVR_SECTOR_NUM)
    {
       ll_eflash_erase_one_sector_nvr(p_eflash, sect_num - LL_EF_MAIN_SECTOR_NUM); 
    }
}


/**
  * @brief  ll_eflash_erase_chip
  * @param  p_eflash: Base address of eflash register
  * @retval None
  */
void ll_eflash_erase_chip(EFLASH_TypeDef *p_eflash)
{
    while((p_eflash->DONE & LL_EF_DONE_CHIP_ERASE_DONE) != LL_EF_DONE_CHIP_ERASE_DONE);
    
    ll_eflash_main_lock(p_eflash, LL_EF_UNLOCK);

    p_eflash->ERASE_CTRL = LL_EF_ERASE_CTRL_CHIP_ERASE_KICK_START;
    while((p_eflash->DONE & LL_EF_DONE_CHIP_ERASE_DONE) != LL_EF_DONE_CHIP_ERASE_DONE);
}


/**
  * @brief  ll_eflash_crc_calc
  * @param  p_eflash: Base address of eflash register
  * @param  st_address: phsic_addr, align: 4byte
  * @param  len :  align: 4byte  
  * @retval crc32 result
  */
u32 ll_eflash_crc32(EFLASH_TypeDef *p_eflash, u32 st_addr, u32 len)
{
#if  CRC_CHECK_EN
    if(st_addr >= LL_EF_NVR_BASE) {
        p_eflash->CRC_ADDR = LL_EF_CRC_ADDR_NVR_EN |
                             LL_EF_CRC_ADDR(st_addr-LL_EF_NVR_BASE);
    } else {
        p_eflash->CRC_ADDR = st_addr;
    }
    p_eflash->CRC_LEN = len;

    p_eflash->KST |= LL_EF_KST_CRC_KST | LL_EF_KST_CRC_KST_EN;
    while(0 == (p_eflash->DONE & LL_EF_DONE_CRC_DONE));
    
    return p_eflash->CRC_OUT;
#else
#warning "CRC CHECK MUST EN!!!"
    return 0;
#endif
}

/**
  * @brief  ll_eflash_auto_program
  * @param  p_eflash: Base address of eflash register
  * @param  ef_addr: eflash main physic_addr
  * @param  ram_addr: sram start address
  * @param  len
  * @retval None
  */
void ll_eflash_auto_program(EFLASH_TypeDef *p_eflash, u32 ef_addr, u32 ram_addr, u32 len)
{

    ef_addr &= 0xFFFC;

    while((p_eflash->DONE & (LL_EF_DONE_PROG_DONE)) == 0);

    p_eflash->CTRLR0 |= LL_EF_CTRLR0_AUTO_PROGRAM_MODE;
    p_eflash->CTRLR0 &= ~LL_EF_CTRLR0_PROG_RAM_TO_EFLASH_ADD_CRC_EN;

    p_eflash->PROG_ADDR = LL_EF_PROG_ADDR_PROG_BYTE_ADDR(ef_addr);
    
    p_eflash->CRC_ADDR = ram_addr;
    p_eflash->CRC_LEN = len;

    p_eflash->KST |= LL_EF_KST_CRC_KST | LL_EF_KST_CRC_KST_EN;
    while(0 == (p_eflash->DONE & LL_EF_DONE_CRC_DONE));
    
    p_eflash->CTRLR0 &= ~LL_EF_CTRLR0_AUTO_PROGRAM_MODE;
    p_eflash->CTRLR0 |= LL_EF_CTRLR0_PROG_RAM_TO_EFLASH_ADD_CRC_EN;
    
}

/**
  * @brief  ll_eflash_auto_program_nvr
  * @param  p_eflash: Base address of eflash register
  * @param  ef_addr: eflash nvr physic_addr
  * @param  ram_addr: sram start address
  * @param  len
  * @retval None
  */
void ll_eflash_auto_program_nvr(EFLASH_TypeDef *p_eflash, u32 ef_addr, u32 ram_addr, u32 len)
{
//    if(prog_byte_num > LL_EF_PROG_BYTE_NUM4)
//    {
//        return;
//    }
//    if(LL_EF_PROG_BYTE_NUM2 == prog_byte_num)
//    {
//       ef_addr &= 0x1FFFFFFE;
//    }
//    else if(LL_EF_PROG_BYTE_NUM4 == prog_byte_num)
//    {
       ef_addr &= 0x1FFFFFFC;
//    }
    while((p_eflash->DONE & (LL_EF_DONE_PROG_DONE)) == 0);

    p_eflash->CTRLR0 |= LL_EF_CTRLR0_AUTO_PROGRAM_MODE;

    p_eflash->PROG_ADDR = LL_EF_PROG_ADDR_PROG_BYTE_ADDR(ef_addr) | LL_EF_PROG_ADDR_PROG_NVR_EN;
    
    p_eflash->CRC_ADDR = ram_addr;
    p_eflash->CRC_LEN = len;

    p_eflash->KST |= LL_EF_KST_CRC_KST | LL_EF_KST_CRC_KST_EN;
    while(0 == (p_eflash->DONE & LL_EF_DONE_CRC_DONE));
    
    p_eflash->CTRLR0 &= ~LL_EF_CTRLR0_AUTO_PROGRAM_MODE;
    
}

/**
  * @brief  The CRC value is added at the end when the RAM data is copied to EFLASH enable
  * @param  p_eflash: Base address of eflash register
  * @retval None
  */
void ll_eflash_prog_ram_to_eflash_add_crc_enable(EFLASH_TypeDef *p_eflash)
{
    p_eflash->CTRLR0  |= LL_EF_CTRLR0_PROG_RAM_TO_EFLASH_ADD_CRC_EN;
}

/**
  * @brief  The CRC value is added at the end when the RAM data is copied to EFLASH disable
  * @param  p_eflash: Base address of eflash register
  * @retval None
  */
void ll_eflash_prog_ram_to_eflash_add_crc_disable(EFLASH_TypeDef *p_eflash)
{
    p_eflash->CTRLR0  &= (~LL_EF_CTRLR0_PROG_RAM_TO_EFLASH_ADD_CRC_EN);
}

/**
  * @brief  ll_eflash_crc_out_result_get
  * @param  p_eflash: Base address of eflash register
  * @retval crc result
  * @note   CRC results, polynomial crc-32 is as follows, the results out of the inverse is the official results  
            write EFLASH CRC need to take the official value of the inverse!!!  
            X32 + x26 + x23 + x22 + x16 + x12 + x11 + + by 8 x10 + + x 5 x7 + x4 + x2 + x + 1  
  */
u32 ll_eflash_crc_out_result_get(EFLASH_TypeDef *p_eflash)
{
    return (u32)(p_eflash->CRC_OUT);
}

/**
  * @brief  ll_eflash_cfg_sector_main_get
  * @param  p_eflash: Base address of eflash register
  * @retval cfg sector
  * @note   Sector location configured by the MAIN user
  */
u32 ll_eflash_cfg_sector_main_get(EFLASH_TypeDef *p_eflash)
{
    return (p_eflash->CFG_SECTOR);
}

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/*************************** (C) COPYRIGHT 2022 JUSHENG ***** END OF FILE *****/
